package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.zmj.sy.mom.srv.aps.bean.entity.base.*;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.Customer;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.Factory;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.Phase;
import com.zmj.sy.mom.srv.aps.bean.vo.base.*;
import com.zmj.sy.mom.srv.aps.bean.vo.importframe.*;
import com.zmj.sy.mom.srv.aps.bean.vo.order.OrderExternalSyncErrorResVo;
import com.zmj.sy.mom.srv.aps.config.StrategyConfig;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.*;
import com.zmj.sy.mom.srv.aps.utils.nest.NestRule;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
@Slf4j
public class ImportFrameService {

    private final ImportFrameOrderMapper importFrameOrderMapper;

    private final ImportFrameBomMapper importFrameBomMapper;

    private final ImportFramePhaseMapper importFramePhaseMapper;
    private final ProcessChainMapper processChainMapper;
    private final ProcessChainItemMapper processChainItemMapper;
    private final PhaseGroupMapper phaseGroupMapper;
    private final OrderMapper orderMapper;
    private final OrderBomMapper orderBomMapper;
    private final OrderPhaseMapper orderPhaseMapper;
    private final ImportErpBomMapper importErpBomMapper;
    private final ImportErpOrderMapper importErpOrderMapper;
    private final ImportErpMaterMapper importErpMaterMapper;
    private final ImportErpWorkOrderMapper importErpWorkOrderMapper;
    private final ImportErpWorkOrderDetailMapper importErpWorkOrderDetailMapper;
    private final ImportErpMappingMapper importErpMappingMapper;
    private final CustomerMapper customerMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final PhaseMapper phaseMapper;
    private final PhaseJobMapper phaseJobMapper;
    private final PhaseJobRefMapper phaseJobRefMapper;
    private final StrategyConfig strategyConfig;

    private final FactoryMapper factoryMapper;

    @Transactional(readOnly = true)
    public BasePageResVo<ImportFrameOrderListResVo> orderList(ImportFrameOrderListReqVo reqVo) {

        Page<ImportFrameOrder> page = importFrameOrderMapper.lambdaQuery()
                .like(StringUtils.hasText(reqVo.getMyCode()), ImportFrameOrder::getMyCode, reqVo.getMyCode())
                .like(StringUtils.hasText(reqVo.getName()), ImportFrameOrder::getName, reqVo.getName())
                .eq(reqVo.getType() != null, ImportFrameOrder::getType, reqVo.getType())
                .orderByDesc(ImportFrameOrder::getId)
                .page(reqVo.toPage());

        return BasePageResVo.of(page, ImportFrameOrderListResVo.class);
    }

    @Transactional
    public void orderAdd(ImportFrameOrderAddReqVo reqVo) {
        ImportFrameOrder importFrameOrder = MkBeanUtils.copyProperties(reqVo, ImportFrameOrder.class);
        importFrameOrderMapper.insert(importFrameOrder);
    }

    @Transactional
    public void orderEdit(ImportFrameOrderEditReqVo reqVo) {
        ImportFrameOrder importFrameOrder = importFrameOrderMapper.selectById(reqVo.getId());
        MkBeanUtils.copyPropertiesIgnore(reqVo, importFrameOrder);
        importFrameOrderMapper.updateById(importFrameOrder);
    }

    @Transactional
    public void orderDel(BaseIdReqVo reqVo) {

        importFrameOrderMapper.deleteRealId(reqVo.getId());
        importFrameBomMapper.deleteByOrderId(reqVo.getId());
        importFramePhaseMapper.deleteByOrderId(reqVo.getId());
    }

    @Transactional(readOnly = true)
    public BaseListResVo<ImportFrameBomTreeResVo> bomTree(BaseIdReqVo reqVo) {
        List<ImportFrameBom> bomList = importFrameBomMapper.lambdaQuery().eq(ImportFrameBom::getOrderId, reqVo.getId()).list();
        List<ImportFrameBomTreeResVo> collect = bomList.stream()
                .map(e -> {
                    ImportFrameBomTreeResVo r = new ImportFrameBomTreeResVo();
                    BeanUtils.copyProperties(e, r);
                    return r;
                })

                .collect(Collectors.toList());
        return new BaseListResVo<>(collect);
    }

    @Transactional(readOnly = true)
    public BaseListResVo<ImportFrameBomListResVo> bomList(BaseIdReqVo reqVo) {

        LambdaQueryWrapper<ImportFrameBom> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ImportFrameBom::getId, reqVo.getId());
        wrapper.or();
        wrapper.eq(ImportFrameBom::getPid, reqVo.getId());
        List<ImportFrameBom> orderBomList = importFrameBomMapper.selectList(wrapper);

        if(CollUtil.isEmpty(orderBomList)){
            return BaseListResVo.empty();
        }

        BaseListResVo<ImportFrameBomListResVo> resVo = BaseListResVo.of(orderBomList, ImportFrameBomListResVo.class);

        ImportFrameOrder order = importFrameOrderMapper.selectById(orderBomList.get(0).getOrderId());
        for (ImportFrameBomListResVo datum : resVo.getData()) {
            datum.setOrderCode(order.getMyCode());
            datum.setConstructNo(order.getMyCode());
            datum.setWeight(datum.getMaterWeight());
        }

        return resVo;
    }

    @Transactional
    public void bomAdd(ImportFrameBomAddReqVo reqVo) {
        ImportFrameBom orderBom = MkBeanUtils.copyProperties(reqVo, ImportFrameBom.class);

        if(reqVo.getPid() == null){
            throw SyExceptionUtils.e("请选择父节点");
        }
        ImportFrameBom parent = importFrameBomMapper.selectById(reqVo.getPid());

        if(!parent.getMaterType().equals("Assembly")){
            throw SyExceptionUtils.e("父节点不是组件");
        }
        if(reqVo.getReadyType() == null){
            throw SyExceptionUtils.e("没有备料方式");
        }
        if (reqVo.getReadyType().equals(2)) {
            orderBom.setWorkChain("WL");
            parent.setMaterType("Component");
        } else {
            orderBom.setWorkChain("");
            parent.setMaterType("Platepart");

        }
        orderBom.setErpCode(reqVo.getErpCode());// 添加

        if (parent.getMaterType() == null) {
            throw SyExceptionUtils.e("没有物料类型");
        }

        orderBom.setMaterCode(orderBom.getPlmId());
        orderBom.setTopFlag(0);
        orderBom.setModifyStatus(LocalDateTime.now().format(DatePattern.PURE_DATETIME_FORMATTER));
        orderBom.setOrderId(parent.getOrderId());
        orderBom.setFactoryNo(parent.getFactoryNo());
        orderBom.setLevel(parent.getLevel() + 1);
        orderBom.setTotalCount(parent.getTotalCount().multiply(orderBom.getPartCount()));
        orderBom.setAssemblyPath(parent.getAssemblyPath() + "/" + orderBom.getMaterCode());
        orderBom.setMaterWeight(reqVo.getWeight());
        orderBom.setMaterHigh(reqVo.getMaterHigh());
        if(!StringUtils.hasText(orderBom.getDrawing())){
            orderBom.setDrawing(orderBom.getPlmId());
        }

        if (reqVo.getReadyType() != 2) {
            ProcessChain processChain = processChainMapper.selectById(reqVo.getProcessChainId());
            orderBom.setWorkChain(processChain.getMyCode());
        }

        importFrameBomMapper.insert(orderBom);

        if (reqVo.getReadyType() != 2) {
            List<ProcessChainItem> itemList = processChainItemMapper.lambdaQuery().eq(ProcessChainItem::getChainId, reqVo.getProcessChainId()).orderByAsc(ProcessChainItem::getSeq).list();

            List<ImportFramePhase> collect = itemList.stream()
                    .map(e -> {
                        ImportFramePhase item = new ImportFramePhase();
                        item.setBomId(orderBom.getId());
                        item.setOrderId(orderBom.getOrderId());
                        item.setWorkChain(orderBom.getWorkChain());
                        item.setPhaseName(e.getName());
                        item.setPhaseCode(e.getMyCode());
                        item.setPhaseSeq(e.getSeq());
                        item.setMaterNo(orderBom.getMaterCode());
                        item.setMaterName(orderBom.getMaterName());
                        if (item.getPhaseCode().equals("FM")) {
                            item.setWorkGroupNumber("4-3_FM_00");
                            item.setWorkTime(0);
                        } else if (item.getPhaseCode().equals("PT")) {
                            item.setWorkGroupNumber("4-3_PTX_00");
                            item.setWorkTime(10 * 60);
                        }
                        item.setOriWorkTime(item.getWorkTime());

                        return item;
                    })
                    .collect(Collectors.toList());

            importFramePhaseMapper.insertBatchSomeColumn(collect);
        }

        // 将 orderBom 进行写入，如果该条数据的父节点原本为普通节点，则要跟随修改其父节点的类别数据
        if (Objects.equals(orderBom.getMaterType(), "Platepart")) {
            orderBom.setStandards(orderBom.getTexture() + "δ" + orderBom.getMaterHigh());
        }

        importFrameBomMapper.updateById(orderBom);
    }

    @Transactional
    public void bomEdit(ImportFrameBomEditReqVo reqVo) {
        ImportFrameBom orderBom = MkBeanUtils.copyProperties(reqVo, ImportFrameBom.class);

        if(reqVo.getPid() == null){
            throw SyExceptionUtils.e("请选择父节点");
        }

        ImportFrameBom parent = importFrameBomMapper.selectById(reqVo.getPid());

        if(!parent.getMaterType().equals("Assembly")){
            throw SyExceptionUtils.e("父节点不是组件");
        }

        if(reqVo.getReadyType() == null){
            throw SyExceptionUtils.e("没有备料方式");
        }

        if (reqVo.getReadyType().equals(2)) {
            orderBom.setWorkChain("WL");
            parent.setMaterType("Component");
        } else {
            orderBom.setWorkChain("");
            parent.setMaterType("Platepart");

        }
        orderBom.setErpCode(reqVo.getErpCode());// 添加

        if (parent.getMaterType() == null) {
            throw SyExceptionUtils.e("没有物料类型");
        }

        orderBom.setMaterCode(orderBom.getPlmId());
        orderBom.setTopFlag(0);
        orderBom.setModifyStatus(LocalDateTime.now().format(DatePattern.PURE_DATETIME_FORMATTER));
        orderBom.setOrderId(parent.getOrderId());
        orderBom.setFactoryNo(parent.getFactoryNo());
        orderBom.setLevel(parent.getLevel() + 1);
        orderBom.setTotalCount(parent.getTotalCount().multiply(orderBom.getPartCount()));
        orderBom.setAssemblyPath(parent.getAssemblyPath() + "/" + orderBom.getMaterCode());
        orderBom.setMaterWeight(reqVo.getWeight());
        orderBom.setMaterHigh(reqVo.getMaterHigh());
        if(!StringUtils.hasText(orderBom.getDrawing())){
            orderBom.setDrawing(orderBom.getPlmId());
        }

        if (reqVo.getReadyType() != 2) {
            ProcessChain processChain = processChainMapper.selectById(reqVo.getProcessChainId());
            orderBom.setWorkChain(processChain.getMyCode());
        }

//        importFrameBomMapper.updateById(orderBom);

        importFramePhaseMapper.deleteHard(orderBom.getId());

        if (reqVo.getReadyType() != 2) {
            List<ProcessChainItem> itemList = processChainItemMapper.lambdaQuery().eq(ProcessChainItem::getChainId, reqVo.getProcessChainId()).orderByAsc(ProcessChainItem::getSeq).list();

            List<ImportFramePhase> collect = itemList.stream()
                    .map(e -> {
                        ImportFramePhase item = new ImportFramePhase();
                        item.setBomId(orderBom.getId());
                        item.setOrderId(orderBom.getOrderId());
                        item.setWorkChain(orderBom.getWorkChain());
                        item.setPhaseName(e.getName());
                        item.setPhaseCode(e.getMyCode());
                        item.setPhaseSeq(e.getSeq());
                        item.setMaterNo(orderBom.getMaterCode());
                        item.setMaterName(orderBom.getMaterName());
                        if (item.getPhaseCode().equals("FM")) {
                            item.setWorkGroupNumber("4-3_FM_00");
                            item.setWorkTime(0);
                        } else if (item.getPhaseCode().equals("PT")) {
                            item.setWorkGroupNumber("4-3_PTX_00");
                            item.setWorkTime(10 * 60);
                        }
                        item.setOriWorkTime(item.getWorkTime());

                        return item;
                    })
                    .collect(Collectors.toList());

            importFramePhaseMapper.insertBatchSomeColumn(collect);
        }

        // 将 orderBom 进行写入，如果该条数据的父节点原本为普通节点，则要跟随修改其父节点的类别数据
        if (Objects.equals(orderBom.getMaterType(), "Platepart")) {
            orderBom.setStandards(orderBom.getTexture() + "δ" + orderBom.getMaterHigh());
        }

        importFrameBomMapper.updateById(orderBom);
    }

    @Transactional
    public void bomDel(BaseIdReqVo reqVo) {

        importFramePhaseMapper.deleteHard(reqVo.getId());

        importFrameBomMapper.deleteHard(reqVo.getId());
    }

    @Transactional(readOnly = true)
    public BaseListResVo<ImportFrameBomPhaseResVo> bomPhase(BaseIdReqVo reqVo) {

        ImportFrameBom bom = importFrameBomMapper.selectById(reqVo.getId());
        if (bom == null) {
            throw SyExceptionUtils.e("BOM不存在");
        }


        LambdaQueryWrapper<ImportFramePhase> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ImportFramePhase::getBomId, reqVo.getId());
        wrapper.orderByAsc(ImportFramePhase::getPhaseSeq);
        List<ImportFramePhase> orderPhases = importFramePhaseMapper.selectList(wrapper);
        List<ImportFrameBomPhaseResVo> collect = orderPhases.stream()
                .map(e -> {
                    ImportFrameBomPhaseResVo target = MkBeanUtils.copyProperties(e, ImportFrameBomPhaseResVo.class);
                    target.setGroupCode(e.getWorkGroupNumber());
                    target.setTotalCount(bom.getTotalCount());
                    target.setPartCount(bom.getPartCount());
                    if(e.getWorkTime() != null){
                        target.setWorkTime(new BigDecimal(e.getWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
                    }
                    target.setWorkOrderCode(bom.getWorkOrderCode());
                    return target;
                })
                .collect(Collectors.toList());
        return new BaseListResVo<>(collect);
    }

    @Transactional
    public void phaseEdit(ImportFramePhaseEditReqVo reqVo) {

        if(reqVo.getWorkTime() == null ){
            throw SyExceptionUtils.e("工时不能为空");
        }
        if(!StringUtils.hasText(reqVo.getGroupCode())){
            throw SyExceptionUtils.e("工作组不能为空");
        }

        ImportFramePhase orderPhase = new ImportFramePhase();
        orderPhase.setId(reqVo.getId());
        orderPhase.setWorkGroupNumber(reqVo.getGroupCode());
        orderPhase.setWorkTime(reqVo.getWorkTime().multiply(new BigDecimal(60)).setScale(0, RoundingMode.HALF_UP).intValue());
        importFramePhaseMapper.updateById(orderPhase);

    }

    @Transactional
    public void orderPub(ImportFrameOrderPubReqVo reqVo) {
        ImportFrameOrder importFrameOrder = importFrameOrderMapper.selectById(reqVo.getId());
        List<ImportFrameBom> bomList = importFrameBomMapper.lambdaQuery().eq(ImportFrameBom::getOrderId, reqVo.getId()).list();
        List<ImportFramePhase> phaseList = importFramePhaseMapper.lambdaQuery().eq(ImportFramePhase::getOrderId, reqVo.getId()).list();

        String[] ignoreProp = new String[]{"id", "createDateTime", "modifyDateTime", "deleted", "createUsername", "modifyUsername", "factoryId"};

        Order newOrder = MkBeanUtils.copyProperties(importFrameOrder, Order.class, ignoreProp);
        orderMapper.insert(newOrder);

        Map<Integer, List<ImportFramePhase>> phaseBomIdMap = phaseList.stream().collect(Collectors.groupingBy(ImportFramePhase::getBomId));
        for (ImportFrameBom bom : bomList) {

            OrderBom newBom = MkBeanUtils.copyProperties(bom, OrderBom.class, ignoreProp);
            newBom.setOrderId(newOrder.getId());
            orderBomMapper.insert(newBom);

            List<ImportFramePhase> importFramePhases = phaseBomIdMap.get(bom.getId());
            if(CollUtil.isEmpty(importFramePhases)){
                continue;
            }

            for (ImportFramePhase phase : importFramePhases) {
                OrderPhase newPhase = MkBeanUtils.copyProperties(phase, OrderPhase.class, ignoreProp);
                newPhase.setBomId(newBom.getId());
                newPhase.setOrderId(newOrder.getId());
                orderPhaseMapper.insert(newPhase);
            }

        }

    }

    @Transactional
    public void orderErp(ImportFrameOrderPubReqVo reqVo) {

        List<OrderExternalSyncErrorResVo> errorList = new ArrayList<>();

        ImportErpBom currentBom = importErpBomMapper.selectById(reqVo.getId());
        if (currentBom == null) {
            throw SyExceptionUtils.e("没有找到该节点，请刷新后重试");
        }

        if ("R".equals(currentBom.getStatusId())) {
            throw SyExceptionUtils.e("该节点状态异常");
        }

        Integer count = importFrameBomMapper.lambdaQuery().eq(ImportFrameBom::getOrderId, reqVo.getTargetId()).count();
        if(count > 0){
            throw SyExceptionUtils.e("该架型下有BOM数据，请先清空再导入");
        }

        ImportErpOrder importErpOrder = importErpOrderMapper.selectById(currentBom.getErpOrderId());

        // 获取所有的子节点
        List<ImportErpBom> allBomTree = findAllTree(importErpOrder);

        // 获取可用的的子节点
        List<ImportErpBom> bomChildren = findBomChildren(currentBom);

        List<String> materCodeList = bomChildren.stream().map(ImportErpBom::getMaterialCode).collect(Collectors.toList());

        // 获取所有的物料信息组成Map，供BOM使用
        List<ImportErpMater> materList = getMaterMap(currentBom.getErpOrderId(), materCodeList);

        // 获取所有的工单信息组成Map，供BOM使用
        List<ImportErpWorkOrder> erpWorkOrderList = getWorkOrderMap(currentBom.getErpOrderId(), materCodeList);

        // 获取所有的工单明细组成Map，供BOM使用
        List<ImportErpWorkOrderDetail> workOrderDetailList = getWorkOrderDetailMap(currentBom.getErpOrderId(), materCodeList);

        // 获取所有的工序映射，供BOM使用
        List<ImportErpMapping> importErpMappings = importErpMappingMapper.selectList(null);

        // 转换订单
        Optional<ImportErpMater> first = materList.stream().filter(e -> e.getMaterialCode().equals(currentBom.getMaterialCode())).findFirst();
        if (!first.isPresent()) {
            throw SyExceptionUtils.e("找不到对应的物料信息");
        }
        Order order = conversionOrder(importErpOrder, currentBom, first.get(), errorList);

        ImportFrameOrder newOrder = importFrameOrderMapper.selectById(reqVo.getTargetId());

        // 保存订单
        saveOrder(order, newOrder, errorList);

        // 转换BOM
        List<ImportFrameBom> orderBomList = conversionBom(order, newOrder, importErpOrder, allBomTree, bomChildren, materList, erpWorkOrderList, workOrderDetailList, importErpMappings, errorList);

        // 转换工序
        List<ImportFramePhase> orderPhaseList = conversionPhase(order, newOrder, orderBomList, workOrderDetailList, importErpMappings, errorList);
        savePhase(orderPhaseList);


        String key = "mom-srv-aps:order-sync:error:" + order.getConstructNo() + ":" + first.get().getPlmId();
        if (CollUtil.isNotEmpty(errorList)) {
            // 存redis
            stringRedisTemplate.opsForValue()
                    .set(key, JsonUtils.toJsonString(errorList), 10, TimeUnit.DAYS);

            throw SyExceptionUtils.e("同步失败，请查看Excel的错误信息");
        }
        stringRedisTemplate.delete(key);

    }

    public void saveOrder(Order order, ImportFrameOrder newOrder, List<OrderExternalSyncErrorResVo> errorList) {
        Integer extracted = getSerialNum(order.getConstructNo(), order.getOrderType());
        order.setSerialNum(extracted);
        order.setSerialCode(String.format("%04d-", order.getSerialNum()) + order.getConstructNo());


        Customer customer = customerMapper.selectById(3);
        if(customer == null){
            throw SyExceptionUtils.e("没有找到该客户");
        }

        order.setCustomerId(3);
        order.setCustomerCode(customer.getMyCode());
        order.setCustomerName(customer.getName());
        order.setOrderPriority(1);
        order.setOrderWeight(1);

    }

    public void savePhase(List<ImportFramePhase> orderPhaseList) {
        if(CollUtil.isEmpty(orderPhaseList)){
            return ;
        }
        importFramePhaseMapper.insertBatchSomeColumn(orderPhaseList);
    }

    public List<ImportFramePhase> conversionPhase(Order order, ImportFrameOrder newOrder, List<ImportFrameBom> bomList, List<ImportErpWorkOrderDetail> workOrderDetailList, List<ImportErpMapping> importErpMappings, List<OrderExternalSyncErrorResVo> errorList) {

        List<Phase> phaseList = phaseMapper.lambdaQuery().list();
        Map<Integer, Phase> phaseIdMap = phaseList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        List<PhaseJob> phaseJobList = phaseJobMapper.lambdaQuery().list();
        Map<Integer, PhaseJob> phaseJobIdMap = phaseJobList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        List<PhaseJobRef> phaseJobRefList = phaseJobRefMapper.lambdaQuery().list();
        Map<String, List<PhaseJobRef>> phaseCodeRefJob = phaseJobRefList.stream().sorted(Comparator.comparing(PhaseJobRef::getSeq)).collect(Collectors.groupingBy(e -> phaseIdMap.get(e.getPhaseId()).getMyCode(), LinkedHashMap::new, Collectors.toList()));
        Map<String, List<PhaseJob>> phaseJobMap = new HashMap<>();
        for (String s : phaseCodeRefJob.keySet()) {
            phaseJobMap.put(s, new ArrayList<>());
            List<PhaseJobRef> phaseJobRefs = phaseCodeRefJob.get(s);
            if(CollUtil.isNotEmpty(phaseJobRefs)){
                phaseJobMap.put(s, phaseJobRefs.stream()
                        .sorted(Comparator.comparing(PhaseJobRef::getSeq))
                        .map(e -> {
                            return phaseJobIdMap.get(e.getPhaseJobId());
                        })
                        .collect(Collectors.toList()));
            }
        }



        Map<String, Map<String, ImportErpMapping>> erpMesOpMappingMap = importErpMappings.stream().collect(Collectors.groupingBy(ImportErpMapping::getErpOpCode, Collectors.toMap(ImportErpMapping::getErpOp, Function.identity(), (e1, e2) -> e1)));

        Map<String, Map<String, List<ImportErpWorkOrderDetail>>> workOrderCodeMaterialCodeMap = workOrderDetailList.stream()
                .collect(
                        Collectors.groupingBy(
                                ImportErpWorkOrderDetail::getWorkOrderCode,
                                Collectors.groupingBy(
                                        ImportErpWorkOrderDetail::getMaterialCode
                                )
                        )
                );

        List<ImportFramePhase> orderPhaseList = new ArrayList<>();
        bomList.sort(Comparator.comparing(ImportFrameBom::getPlmId));

        Map<Integer, ImportFrameBom> orderBomMap = bomList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        for (ImportFrameBom bom : bomList) {

            Map<String, List<ImportErpWorkOrderDetail>> stringListMap = workOrderCodeMaterialCodeMap.get(bom.getWorkOrderCode());
            if (stringListMap == null) {
                continue;
            }

            List<ImportErpWorkOrderDetail> importErpWorkOrderDetails = stringListMap.get(bom.getBomCode());
            if (importErpWorkOrderDetails == null) {
                continue;
            }

            BigDecimal reduce = importErpWorkOrderDetails.stream().reduce(BigDecimal.ZERO, (a, b) -> a.add(new BigDecimal(b.getSdgs() == null? "0" : b.getSdgs())), BigDecimal::add);
            if (!bom.getWorkChain().equals("WL") && reduce.compareTo(BigDecimal.ZERO) == 0) {

                bom.setMaterType("Component");
                bom.setWorkChain("WL");//外协件定值
                bom.setReadyType(2);
                importFrameBomMapper.updateById(bom);
                continue;
            }

            int phaseSeq = 1;

            if (bom.getMaterType().equals("Platepart")) {
                ImportFramePhase phase = new ImportFramePhase();
                phase.setOrderId(newOrder.getId());
                phase.setBomId(bom.getId());
                phase.setWorkTime(0);
                phase.setWorkChain(bom.getWorkChain());
                phase.setPhaseSeq(phaseSeq++);
                phase.setMaterNo(bom.getPlmId());
                phase.setMaterName(bom.getMaterName());
                phase.setPhaseCode(WorkshopProp.LL_PHASE_CODE);
                phase.setPhaseName(WorkshopProp.LL_PHASE_NAME);
                phase.setWorkGroupNumber(WorkshopProp.LL_GROUP);
                phase.setOriWorkTime(phase.getWorkTime());
                orderPhaseList.add(phase);
            }

            Map<String, Integer> phaseCount = new HashMap<>();
            importErpWorkOrderDetails.sort(Comparator.comparing(ImportErpWorkOrderDetail::getSeq));
            for (ImportErpWorkOrderDetail detail : importErpWorkOrderDetails) {
                ImportFramePhase phase = new ImportFramePhase();
                phase.setOrderId(newOrder.getId());
                phase.setBomId(bom.getId());

                //工时取sdgs
                if (detail.getSdgs() != null) {
                    phase.setWorkTime(new BigDecimal(detail.getSdgs()).multiply(new BigDecimal(60)).setScale(0, RoundingMode.UP).intValue());
                } else {
                    phase.setWorkTime(0);
                }
                phase.setOriWorkTime(phase.getWorkTime());

                //detailEntity.setProdSn(z.getSn());
                phase.setWorkChain(bom.getWorkChain());
                phase.setMaterNo(bom.getPlmId());
                phase.setMaterName(detail.getMaterialName());
                if(!detail.getOpCode().trim().startsWith("170")){
                    continue;
                }
                if (erpMesOpMappingMap.get(detail.getOpCode()) == null) {
                    errorList.add(new OrderExternalSyncErrorResVo(4, detail.getMaterialName() + detail.getMaterialCode() + "工作中心编码【" + detail.getOpCode() + "】,缺工序编码【" + detail.getOp() + "】,请先维护工作中心映射!", order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
//                    throw SyExceptionUtils.e("根据ERP工作中心编码“" + detail.getOpCode().trim() + "”未能找到对应的MES工作中心映射关系，请先维护工作中心映射!");
                    continue;

                }
                ImportErpMapping importErpMapping = null;
                if (detail.getOpCode().startsWith("129")) {
                    importErpMapping = erpMesOpMappingMap.get("129002").get("Z206");
                } else {
                    importErpMapping = erpMesOpMappingMap.get(detail.getOpCode()).get(detail.getOp());
                }

                if (importErpMapping == null) {
                    errorList.add(new OrderExternalSyncErrorResVo(4, detail.getMaterialName() + detail.getMaterialCode() + "工作中心编码【" + detail.getOpCode() + "】,缺工序编码【" + detail.getOp() + "】,请先维护工作中心映射!", order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
                    continue;
                }
                Integer count = phaseCount.compute(importErpMapping.getMesWorkPhase(), (k, v) -> v == null ? 0 : v + 1);
                String phaseCodeCount = importErpMapping.getMesWorkPhase();

                if (count > 0) {
                    phaseCodeCount = importErpMapping.getMesWorkPhase() + String.format("%02d", count);
                }
                phase.setPhaseCode(phaseCodeCount);
                phase.setPhaseSeq(phaseSeq++);
                phase.setPhaseName(importErpMapping.getApsPhaseName());
                phase.setWorkGroupNumber(importErpMapping.getMesWorkCenter());

                if(phase.getWorkTime().compareTo(0) > 0){
                    // 工序任务处理
                    List<PhaseJob> job = phaseJobMap.get(phase.getPhaseCode());
                    if (CollUtil.isNotEmpty(job)) {
                        int jobTime = TaskTimeUtils.calcJobTime(phase, job);
                        phase.setOriWorkTime(phase.getWorkTime());
                        phase.setWorkTime(phase.getWorkTime() + jobTime);

                    }
                }

//                phase.setOriWorkTime(new BigDecimal(phase.getWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.UP));
                orderPhaseList.add(phase);

                if(bom.getWorkChain().equals("WL") && (phase.getPhaseCode().equals("JG") || phase.getPhaseCode().equals("HG"))){
                    errorList.add(new OrderExternalSyncErrorResVo(2, detail.getMaterialName() + detail.getMaterialCode() + "数据异常, 类型识别为WL，但是有切割工序", order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
                }
            }

            if (bom.getPid() != null ) {
                if(bom.getMaterType().equals("Platepart") || (bom.getMaterType().equals("Assembly") && !MkPartUtils.supportKjPhase(bom.getPlmId(), bom.getMaterName()))){
                    ImportFrameBom parentBom = orderBomMap.get(bom.getPid());
                    if (MkPartUtils.supportKjPhase(parentBom.getPlmId(), parentBom.getMaterName())) {
                        ImportFramePhase phase = new ImportFramePhase();
                        phase.setOrderId(newOrder.getId());
                        phase.setBomId(bom.getId());
                        phase.setWorkTime(1);
                        phase.setOriWorkTime(phase.getWorkTime());
                        phase.setWorkChain(bom.getWorkChain());
                        phase.setPhaseSeq(phaseSeq++);
                        phase.setMaterNo(bom.getPlmId());
                        phase.setMaterName(bom.getMaterName());
                        phase.setPhaseCode(WorkshopProp.KJ_PHASE_CODE);
                        phase.setPhaseName(WorkshopProp.KJ_PHASE_NAME);
                        phase.setWorkGroupNumber(WorkshopProp.KJ_GROUP);
                        orderPhaseList.add(phase);
                    }
                }
            }
        }

        return orderPhaseList;
    }

    public List<ImportErpBom> findAllTree(ImportErpOrder order) {
        return importErpBomMapper.selectList(Wrappers.<ImportErpBom>query().eq("erp_order_id", order.getId()));
    }

    public List<ImportErpBom> findBomChildren(ImportErpBom currentBom) {

        List<ImportErpBom> importErpBoms = importErpBomMapper.tree(currentBom.getErpOrderId());

        Map<String, List<ImportErpBom>> pmCodeList = importErpBoms.stream().collect(Collectors.groupingBy(ImportErpBom::getPmCode));

        List<ImportErpBom> l = new ArrayList<>();

        List<ImportErpBom> temp = new ArrayList<>();
        temp.add(currentBom);
        currentBom.setIsTop(1);

        while (!temp.isEmpty()) {
            List<ImportErpBom> t = new ArrayList<>();
            for (ImportErpBom importErpBom : temp) {
                List<ImportErpBom> importErpBoms1 = pmCodeList.get(importErpBom.getMaterialCode());
                if (importErpBoms1 == null) {
                    continue;
                }
                for (ImportErpBom erpBom : importErpBoms1) {
                    erpBom.setIsTop(0);
                }
                t.addAll(importErpBoms1);
            }
            l.addAll(temp);
            temp = t;
        }
        return l;
    }


    public List<ImportErpMater> getMaterMap(Integer erpOrderId, List<String> materCodeList) {

        QueryWrapper<ImportErpMater> query = Wrappers.query();
        query.eq("erp_order_id", erpOrderId);
        return importErpMaterMapper.selectList(query);
    }

    public List<ImportErpWorkOrder> getWorkOrderMap(Integer erpOrderId, List<String> bomChildren) {
        LambdaQueryWrapper<ImportErpWorkOrder> query = Wrappers.lambdaQuery();
        query.in(ImportErpWorkOrder::getMaterialCode, bomChildren);
        query.eq(ImportErpWorkOrder::getErpOrderId, erpOrderId);
        return importErpWorkOrderMapper.selectList(query);
    }


    public List<ImportErpWorkOrderDetail> getWorkOrderDetailMap(Integer erpOrderId, List<String> materCodeList) {
        QueryWrapper<ImportErpWorkOrderDetail> query = Wrappers.query();
        query.in("material_code", materCodeList);
        query.eq("erp_order_id", erpOrderId);
        return importErpWorkOrderDetailMapper.selectList(query);
    }

    public Order conversionOrder(ImportErpOrder importErpOrder, ImportErpBom currentBom, ImportErpMater importErpMater, List<OrderExternalSyncErrorResVo> errorList) {
        Order order = new Order();
        order.setOrderCode(importErpOrder.getOrderCode());
        order.setConstructNo(importErpOrder.getOrderCode());
        order.setMaterCode(currentBom.getGraphNo());
        order.setMaterName(currentBom.getMaterialName());
        order.setOrderQty(NumberUtil.parseInt(importErpOrder.getQty()));
        order.setFinishQty(0);
        if (importErpOrder.getOrderCode().startsWith("J")) {
            order.setOrderType(4);
        } else {
            order.setOrderType(1);
        }
        order.setOrderStatus(1);
        order.setOrderDateTime(importErpOrder.getAssignDate());
        order.setDeliveryDateTime(importErpOrder.getDeliTime());
        order.setPlmId(importErpMater.getPlmId());

        Customer customer = customerMapper.selectById(3);
        if(customer == null){
            throw SyExceptionUtils.e("没有找到该客户");
        }

        order.setCustomerId(3);
        order.setCustomerCode(customer.getMyCode());
        order.setCustomerName(customer.getName());
        order.setOrderPriority(1);
        order.setOrderWeight(1);

        Factory line = factoryMapper.lambdaQuery().eq(Factory::getType, 2).eq(Factory::getMyCode, WorkshopProp.DEFAULT_LINE_CODE).one();
        order.setLineId(line.getId());

        return order;
    }

    public List<ImportFrameBom> conversionBom(Order order, ImportFrameOrder newOrder, ImportErpOrder importErpOrder, List<ImportErpBom> allBomTree, List<ImportErpBom> bomChildren, List<ImportErpMater> erpMaterList, List<ImportErpWorkOrder> erpWorkOrderList, List<ImportErpWorkOrderDetail> workOrderDetailListAll, List<ImportErpMapping> importErpMappings, List<OrderExternalSyncErrorResVo> errorList) {
        Map<String, Map<String, ImportErpMapping>> erpMesOpMapping = importErpMappings.stream().collect(Collectors.groupingBy(ImportErpMapping::getErpOpCode, Collectors.toMap(ImportErpMapping::getErpOp, Function.identity(), (e1, e2) -> e1)));
        Map<String, List<ImportErpBom>> bomPmCodeMap = allBomTree.stream().collect(Collectors.groupingBy(ImportErpBom::getPmCode));
        Map<String, ImportErpMater> materCodeMap = erpMaterList.stream().collect(Collectors.toMap(ImportErpMater::getMaterialCode, Function.identity(), (e1, e2) -> e1));
        Map<String, List<ImportErpWorkOrder>> workOrderCodeMap = erpWorkOrderList.stream().collect(Collectors.groupingBy(ImportErpWorkOrder::getMaterialCode));
        Map<String, List<ImportErpWorkOrderDetail>> workOrderDetailMap = workOrderDetailListAll.stream().collect(Collectors.groupingBy(ImportErpWorkOrderDetail::getMaterialCode));
        Map<String, ImportErpBom> parentBom = allBomTree.stream().collect(Collectors.toMap(ImportErpBom::getMaterialCode, Function.identity(), (e1, e2) -> e1));

        List<ImportFrameBom> orderBomList = new ArrayList<>();

        Optional<ImportErpBom> firstOptional = bomChildren.stream().filter(e -> e.getIsTop() == 1).findFirst();
        if (!firstOptional.isPresent()) {
//            errorList.add(new OrderExternalSyncErrorResVo(1, "找不到根节点"));
//            errorList.add(new OrderExternalSyncErrorResVo(1, "找不到根节点：" + importErpOrder.getOrderCode(), importErpOrder.getOrderCode(), null, null, null, null,null, null, null, null, null));
            throw SyExceptionUtils.e("找不到BOM的根节点!");
        }
        ImportErpBom importErpBom = firstOptional.get();
        ImportFrameBom top = swap(order, newOrder, importErpBom, materCodeMap, workOrderCodeMap, workOrderDetailMap, bomPmCodeMap, erpMesOpMapping, parentBom, null, errorList);
        String pattern = ".+" + WorkshopProp.PH_PATTERN;
        if (order.getOrderType() == 1 && !order.getMaterCode().matches(pattern)) {
            ImportFrameBom o = importFrameBomMapper.lambdaQuery().eq(ImportFrameBom::getMaterCode, order.getMaterCode()).eq(ImportFrameBom::getOrderId, order.getId()).one();
            if (o == null) {
                ImportFrameBom orderBom = new ImportFrameBom();
                orderBom.setFactoryNo("170");
                orderBom.setOrderId(newOrder.getId());
                orderBom.setMaterName(order.getMaterName());
                orderBom.setMaterCode(order.getMaterCode());

                int div = Integer.parseInt(importErpOrder.getQty()) / order.getOrderQty();
                if(Integer.parseInt(importErpOrder.getQty()) % order.getOrderQty() != 0){
                    throw SyExceptionUtils.e("订单数量必须为整数倍!");
                }

                if(div < 1){
                    throw SyExceptionUtils.e("当前数量必须大于等于订单数量!");
                }

                orderBom.setPartCount(new BigDecimal(div));
                orderBom.setTotalCount(orderBom.getPartCount());
                orderBom.setBomCode(order.getMaterCode());
                orderBom.setPlmId(order.getMaterCode());
                orderBom.setMaterType("Assembly");
                orderBom.setLevel(1);
                orderBom.setReadyType(1);
                orderBom.setDrawing(orderBom.getDrawing());

                StringBuilder sb = new StringBuilder();

                ImportErpBom currentParent = parentBom.get(orderBom.getBomCode());
                while (currentParent != null) {
                    ImportErpMater importErpMater1 = materCodeMap.get(currentParent.getMaterialCode());
                    if (importErpMater1 == null) {
                        // throw SyExceptionUtils.e("没有找到路径!");
//                        errorList.add(new OrderExternalSyncErrorResVo(2, "找不到零件信息：" + currentParent.getMaterialCode()));
                        errorList.add(new OrderExternalSyncErrorResVo(2, "找不到零件信息：" + currentParent.getMaterialCode(), importErpOrder.getOrderCode(), currentParent.getWorkOrderCode(), currentParent.getMaterialCode(), currentParent.getMaterialName(), null,String.format("%s%s", currentParent.getMaterial(), currentParent.getGrade()), currentParent.getPerReqQty(), currentParent.getPmCode(), currentParent.getStatusId(), null));
                    }
                    sb.insert(0, importErpMater1.getPlmId()).insert(0, "/");
                    currentParent = parentBom.get(currentParent.getPmCode());
                }

                orderBom.setAssemblyPath(sb.toString());
                orderBom.setTopFlag(1);
                orderBom.setWorkChain("WW");
                importFrameBomMapper.insert(orderBom);

                ImportFramePhase topPhase = new ImportFramePhase();
                topPhase.setOrderId(newOrder.getId());
                topPhase.setBomId(orderBom.getId());
                topPhase.setWorkTime(1);
                topPhase.setOriWorkTime(1);
                topPhase.setPhaseSeq(1);
                topPhase.setPhaseCode("WW");
                topPhase.setPhaseName("委外");
                topPhase.setWorkGroupNumber("WW");
                topPhase.setMaterNo(orderBom.getMaterCode());
                topPhase.setMaterName(orderBom.getMaterName());
                topPhase.setWorkChain(orderBom.getWorkChain());
                importFramePhaseMapper.insert(topPhase);

                o = orderBom;
            }
            orderBomList.add(o);
            top.setPid(o.getId());

            orderBomList.add(top);
            top.setLevel(2);
            top.setTopFlag(0);
            top.setAssemblyPath(o.getAssemblyPath() + "/" + top.getDrawing());
            if(!StringUtils.hasText(top.getWorkChain())){
                top.setWorkChain("WW");
            }
            importFrameBomMapper.insert(top);

            if (top.getWorkChain().equals("WW")) {
                OrderPhase llPhase = new OrderPhase();
                llPhase.setOrderId(newOrder.getId());
                llPhase.setBomId(top.getId());
                llPhase.setWorkTime(1);
                llPhase.setOriWorkTime(llPhase.getWorkTime());
                llPhase.setWorkChain(top.getWorkChain());
                llPhase.setPhaseSeq(1);
                llPhase.setMaterNo(top.getMaterCode());
                llPhase.setMaterName(top.getMaterName());
                llPhase.setPhaseCode(WorkshopProp.KJ_PHASE_CODE);
                llPhase.setPhaseName(WorkshopProp.KJ_PHASE_NAME);
                llPhase.setWorkGroupNumber(WorkshopProp.KJ_GROUP);
                llPhase.setWorkChain(top.getWorkChain());
                orderPhaseMapper.insert(llPhase);

                OrderPhase topPhase = new OrderPhase();
                topPhase.setOrderId(newOrder.getId());
                topPhase.setBomId(top.getId());
                topPhase.setWorkTime(1);
                topPhase.setOriWorkTime(topPhase.getWorkTime());
                topPhase.setPhaseSeq(2);
                topPhase.setPhaseCode("WW");
                topPhase.setPhaseName("委外");
                topPhase.setWorkGroupNumber("WW");
                topPhase.setMaterNo(top.getMaterCode());
                topPhase.setMaterName(top.getMaterName());
                topPhase.setWorkChain(top.getWorkChain());
                orderPhaseMapper.insert(topPhase);
            }

        } else {
            orderBomList.add(top);
            importFrameBomMapper.insert(top);
        }


        Map<String, List<ImportErpBom>> collect = bomChildren.stream().collect(Collectors.groupingBy(ImportErpBom::getPmCode));
        List<ImportFrameBom> orderBoms = Lists.newArrayList(top);

        while (!orderBoms.isEmpty()) {
            List<ImportFrameBom> temp = Lists.newArrayList();
            for (ImportFrameBom orderBom : orderBoms) {

                List<ImportErpBom> orderBoms1 = collect.get(orderBom.getBomCode());
                if (orderBoms1 == null) {
                    continue;
                }

                Map<String, ImportFrameBom> map = new HashMap<>();
                for (ImportErpBom bom : orderBoms1) {
                    ImportFrameBom swap = swap(order, newOrder, bom, materCodeMap, workOrderCodeMap, workOrderDetailMap, bomPmCodeMap, erpMesOpMapping, parentBom, orderBom, errorList);
//                    if(orderBom.getWorkChain().equals("WL") && swap.getWorkChain().equals("WL")){
//                        continue;
//                    }

                    ImportFrameBom bomHas = map.get(swap.getPlmId());
                    if(bomHas != null){
                        continue;
                    }
                    map.put(swap.getPlmId(), swap);

                    temp.add(swap);
                    orderBomList.add(swap);
                    importFrameBomMapper.insert(swap);
                }
            }
            orderBoms = temp;

        }

        orderBomList.sort(Comparator.comparing(ImportFrameBom::getBomCode));
        return orderBomList;


    }

    public ImportFrameBom swap(Order order, ImportFrameOrder newOrder, ImportErpBom bom, Map<String, ImportErpMater> materCodeMap, Map<String, List<ImportErpWorkOrder>> workOrderCodeMap, Map<String, List<ImportErpWorkOrderDetail>> workOrderDetailMap, Map<String, List<ImportErpBom>> bomPmCodeMap, Map<String, Map<String, ImportErpMapping>> erpMesOpMapping, Map<String, ImportErpBom> parentBom, ImportFrameBom parent, List<OrderExternalSyncErrorResVo> errorList) {

        ImportFrameBom orderBom = new ImportFrameBom();
        orderBom.setFactoryNo("170");
        orderBom.setOrderId(newOrder.getId());
        orderBom.setPackCenter(bom.getPickCenter());
        orderBom.setMaterName(bom.getMaterialName());
        orderBom.setStandards(bom.getGrade());
        orderBom.setErpCode(bom.getMaterialCode());
        orderBom.setErpParentCode(bom.getPmCode());
        orderBom.setPartCount(NumberUtil.round(bom.getPerReqQty(), 0));
        orderBom.setTopFlag(bom.getIsTop());
        orderBom.setBomCode(bom.getMaterialCode());
        orderBom.setParentBomCode(bom.getPmCode());
        if (parent == null) {
            orderBom.setTotalCount(orderBom.getPartCount());
            orderBom.setLevel(1);
        } else {
            orderBom.setTotalCount(parent.getTotalCount().multiply(orderBom.getPartCount()));
            orderBom.setLevel(parent.getLevel() + 1);
        }

        ImportErpMater importErpMater = materCodeMap.get(bom.getMaterialCode());
        if (importErpMater == null) {
//            throw SyExceptionUtils.e("找不到对应的物料信息");
            orderBom.setMaterCode(bom.getGraphNo());
            if(StringUtils.hasText(orderBom.getMaterCode())){
                orderBom.setMaterCode(orderBom.getMaterCode().replaceAll("/", "-"));
            }
            orderBom.setPlmId(orderBom.getMaterCode());
            orderBom.setDrawing(orderBom.getMaterCode());
            orderBom.setMaterType("Component");
            orderBom.setWorkChain("WL");//外协件定值
            orderBom.setReadyType(2);
            orderBom.setAssemblyPath(parent.getAssemblyPath() + "/" + orderBom.getMaterCode());
            orderBom.setPid(parent.getId());
//            errorList.add(new OrderExternalSyncErrorResVo(2, "找不到零件信息：" + bom.getMaterialCode(), order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterialCode(), bom.getMaterialName(), null,String.format("%s%s", bom.getMaterial(), bom.getGrade()), bom.getPerReqQty(), bom.getPmCode(), bom.getStatusId(), null));
            return orderBom;
        }

        orderBom.setMaterCode(importErpMater.getPaintCode());
        if(StringUtils.hasText(orderBom.getMaterCode())){
            orderBom.setMaterCode(orderBom.getMaterCode().replaceAll("/", "-"));
        }


        orderBom.setPlmId(importErpMater.getPlmId());
        if (orderBom.getPlmId() == null) {
            orderBom.setPlmId("");
        }
        if(StringUtils.hasText(orderBom.getPlmId())){
            orderBom.setPlmId(orderBom.getPlmId().replaceAll("/", "-"));
        }

        if (importErpMater.getNetWeight() != null) {
            orderBom.setMaterWeight(NumberUtil.round(importErpMater.getNetWeight(), 2));
        }

        orderBom.setDrawing(importErpMater.getPaintCode());
        if(StringUtils.hasText(orderBom.getDrawing())){
            orderBom.setDrawing(orderBom.getDrawing().replaceAll("/", "-"));
        }


        List<ImportErpWorkOrder> workOrderList = workOrderCodeMap.get(bom.getMaterialCode());
        ImportErpWorkOrder workOrder = null;
        if (CollUtil.isNotEmpty(workOrderList)) {
            workOrder = findDueDate(workOrderList);
            if (workOrder != null) {
                orderBom.setDueDate(workOrder.getPlanEndTime());
            }
        }

        if (workOrder == null) {
            workOrder = new ImportErpWorkOrder();
            workOrder.setIsComponent("1");
            workOrder.setWorkOrderCode("WO-XXXXXXX");
            workOrder.setWorkOrderType("1");
//                    orderBom.setDueDate(bom.getMarkDate());// 代码有问题，ERP没这个字段，所有注释
        }


        List<ImportErpWorkOrderDetail> workOrderDetailList = workOrderDetailMap.get(bom.getMaterialCode());
        // 如果无工序明细，则为外协件
        if (workOrderDetailList == null) {
            orderBom.setMaterType("Component");
            orderBom.setWorkChain("WL");//外协件定值
            orderBom.setReadyType(workOrder.getIsComponent().equals("1") ? 2 : 1);
        }

        String spec = importErpMater.getSpec();//.replaceAll(REGEX_CHINESE, "");
        if (spec != null) {
            if (spec.contains("组件")) {
                orderBom.setMaterType("Assembly"); // 组件类型，Assembly
            } else if (workOrderDetailList == null) {
                //如果无工序明细，则为外协件
                orderBom.setMaterType("Component");
                orderBom.setWorkChain("WL");//外协件定值
                orderBom.setReadyType("1".equals(workOrder.getIsComponent()) ? 2 : 1);
            } else if (spec.contains("δ")) {
                orderBom.setMaterType("Platepart");//Platepart
                orderBom.setReadyType("1".equals(workOrder.getIsComponent()) ? 2 : 1);

                //施工单 物料号  获取 工单bom
                List<ImportErpBom> plateList = bomPmCodeMap.get(bom.getMaterialCode());
                if (plateList == null || plateList.isEmpty()) {
                    errorList.add(new OrderExternalSyncErrorResVo(2, "找不到对应的板材材质或规格信息", order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterialCode(), bom.getMaterialName(), null,String.format("%s%s", bom.getMaterial(), bom.getGrade()), bom.getPerReqQty(), bom.getPmCode(), bom.getStatusId(), bom.getMaterialCode()));
                    return orderBom;
//                    throw SyExceptionUtils.e("找不到对应的板材材质或规格信息");
                } else {
                    ImportErpBom plateBom = plateList.get(0);
                    if (StringUtils.hasText(plateBom.getMaterial()) && StringUtils.hasText(plateBom.getGrade())) {
                        orderBom.setTexture(plateBom.getMaterial());//材质
                        String str = plateBom.getGrade().replace("δ", "");
                        try {
                            orderBom.setMaterHigh(NumberUtil.round(str, 0).intValue());//厚度

                        } catch (Exception e) {
                            e.printStackTrace();
                            throw e;
                        }
                    } else {
                        errorList.add(new OrderExternalSyncErrorResVo(2, "材质或规格为空", order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterialCode(), bom.getMaterialName(), null,String.format("%s%s", bom.getMaterial(), bom.getGrade()), bom.getPerReqQty(), bom.getPmCode(), bom.getStatusId(), bom.getMaterialCode()));
                        return orderBom;
//                        throw SyExceptionUtils.e("材质或规格为空");
                    }


                }
            } else {
                orderBom.setMaterType("Component");
                orderBom.setWorkChain("WL");//外协件定值
                orderBom.setReadyType("1".equals(workOrder.getIsComponent()) ? 2 : 1);
            }
        }

        //工单类型0-自制；1-外协
        if (workOrder.getWorkOrderType().equals("1")) {
            orderBom.setMaterType("Component");
            orderBom.setWorkChain("WL");//外协件定值
            orderBom.setReadyType(workOrder.getIsComponent().equals("1") ? 2 : null);
        }

        if (orderBom.getMaterType() == null) {
            errorList.add(new OrderExternalSyncErrorResVo(2, "无法判断物料类型!", order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterialCode(), bom.getMaterialName(), null,String.format("%s%s", bom.getMaterial(), bom.getGrade()), bom.getPerReqQty(), bom.getPmCode(), bom.getStatusId(), bom.getMaterialCode()));
            return orderBom;
//            throw SyExceptionUtils.e("无法判断物料类型!");
        }

//            orderBom.setParentMaterNo(orderBom.getDrawing());
        //获取工序链
        if (!orderBom.getMaterType().equals("Component")) {
            String workChain = getWorkChain(workOrderDetailList, erpMesOpMapping, workOrder.getWorkOrderCode(), orderBom, errorList);
            orderBom.setWorkChain(workChain);
        }


        //ERP工单号
        orderBom.setWorkOrderCode(workOrder.getWorkOrderCode());

        // MES需要的路径，如果没用请注释
        if (orderBom.getTopFlag().equals(1)) {
            StringBuilder sb = new StringBuilder();

            ImportErpBom currentParent = parentBom.get(orderBom.getBomCode());
            while (currentParent != null) {
                ImportErpMater importErpMater1 = materCodeMap.get(currentParent.getMaterialCode());
                if (importErpMater1 == null) {
                    errorList.add(new OrderExternalSyncErrorResVo(2, "没有找到路径!", order.getConstructNo(), bom.getWorkOrderCode(), bom.getMaterialCode(), bom.getMaterialName(), null,String.format("%s%s", bom.getMaterial(), bom.getGrade()), bom.getPerReqQty(), bom.getPmCode(), bom.getStatusId(), bom.getMaterialCode()));
                    return orderBom;
//                    throw SyExceptionUtils.e("没有找到路径!");
                }
                sb.insert(0, importErpMater1.getPlmId()).insert(0, "/");
                currentParent = parentBom.get(currentParent.getPmCode());
            }

            orderBom.setAssemblyPath(sb.toString());
        } else {
            orderBom.setAssemblyPath(parent.getAssemblyPath() + "/" + orderBom.getMaterCode());
            orderBom.setPid(parent.getId());
        }

        orderBom.setReadyType(orderBom.getWorkChain().equals("WL") ? 2 : 1);

        return orderBom;
    }

    public String getWorkChain(List<ImportErpWorkOrderDetail> allWorkOrderDetailList, Map<String, Map<String, ImportErpMapping>> erpMesOpMappingMap, String workOrderCode, ImportFrameBom bom, List<OrderExternalSyncErrorResVo> errorList) {
        String workChain = "";
        if (CollUtil.isEmpty(allWorkOrderDetailList)) {
            return workChain;
        }

        List<ImportErpWorkOrderDetail> detailList = allWorkOrderDetailList
                .stream()
                .filter(e -> !"70020604".equals(e.getOpCode()))
                .filter(e -> !"Z105".equals(e.getOp()))
                .filter(e -> workOrderCode.equals(e.getWorkOrderCode()))
                .sorted(Comparator.comparing(ImportErpWorkOrderDetail::getSeq))
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(detailList)) {
            return workChain;
        }

        Map<String, Integer> phaseCount = new HashMap<>();
        for (ImportErpWorkOrderDetail detail : detailList) {

            if (!StringUtils.hasText(detail.getOpCode())) {
//                throw SyExceptionUtils.e("根据ERP工作中心编码“" + detail.getOpCode() + "”,ERP工序编码“" + detail.getOp() + "”,物料编码“" + detail.getMaterialCode() + "”未能找到对应的MES工作中心映射关系，请先维护工作中心映射!");
//                errorList.add("根据ERP工作中心编码“" + detail.getOpCode() + "”,ERP工序编码“" + detail.getOp() + "”,物料编码“" + detail.getMaterialCode() + "”未能找到对应的MES工作中心映射关系，请先维护工作中心映射!");
                errorList.add(new OrderExternalSyncErrorResVo(4, detail.getMaterialName() + detail.getMaterialCode() + "工作中心编码【" + detail.getOpCode() + "】,缺工序编码【" + detail.getOp() + "】,请先维护工作中心映射!", null, bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
                return workChain;
            }

            if(!detail.getOpCode().trim().startsWith("170")){
                continue;
            }

            if (!StringUtils.hasText(detail.getOp())) {
//                throw SyExceptionUtils.e("根据ERP工作中心编码“" + detail.getOpCode() + "”,ERP工序编码“" + detail.getOp() + "”,物料编码“" + detail.getMaterialCode() + "”未能找到对应的MES工作中心映射关系，请先维护工作中心映射!");
//                errorList.add("根据ERP工作中心编码“" + detail.getOpCode() + "”,ERP工序编码“" + detail.getOp() + "”,物料编码“" + detail.getMaterialCode() + "”未能找到对应的MES工作中心映射关系，请先维护工作中心映射!");
                errorList.add(new OrderExternalSyncErrorResVo(4, detail.getMaterialName() + detail.getMaterialCode() + "工作中心编码【" + detail.getOpCode() + "】,缺工序编码【" + detail.getOp() + "】,请先维护工作中心映射!", null, bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
                return workChain;
            }

            if (detail.getOpCode().startsWith("129")) {
                workChain += "ZP-";//如果工作中心以129开头，直接截断后续所有工序，增加ZP工序
                break;
            }

            if (erpMesOpMappingMap.get(detail.getOpCode()) == null) {
//                throw SyExceptionUtils.e("根据ERP工作中心编码“" + detail.getOpCode() + "”,ERP工序编码“" + detail.getOp() + "”,物料编码“" + detail.getMaterialCode() + "”未能找到对应的MES工作中心映射关系，请先维护工作中心映射!");
                errorList.add(new OrderExternalSyncErrorResVo(4, detail.getMaterialName() + detail.getMaterialCode() + "工作中心编码【" + detail.getOpCode() + "】,缺工序编码【" + detail.getOp() + "】,请先维护工作中心映射!", null, bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
                return workChain;
            }
            ImportErpMapping importErpMapping = erpMesOpMappingMap.get(detail.getOpCode()).get(detail.getOp());

            if (importErpMapping == null) {
                errorList.add(new OrderExternalSyncErrorResVo(4, detail.getMaterialName() + detail.getMaterialCode() + "工作中心编码【" + detail.getOpCode() + "】,缺工序编码【" + detail.getOp() + "】,请先维护工作中心映射!", null, bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
//                throw SyExceptionUtils.e("根据ERP工作中心编码“" + detail.getOpCode() + "”,ERP工序编码“" + detail.getOp() + "”,物料编码“" + detail.getMaterialCode() + "”未能找到对应的MES工作中心映射关系，请先维护工作中心映射!");
            } else {
                String str = importErpMapping.getMesWorkPhase();
                Integer count = phaseCount.compute(str, (k, v) -> v == null ? 0 : v + 1);
                String phaseCodeCount = str + "-";
                if (count > 0) {
                    phaseCodeCount = str + String.format("%02d", count) + "-";
                }
                workChain += phaseCodeCount;
            }
        }
        if (org.apache.commons.lang.StringUtils.isNotBlank(workChain)) {
            workChain = workChain.substring(0, workChain.length() - 1);
        } else {
//            throw SyExceptionUtils.e("工序链生成失败！");
            errorList.add(new OrderExternalSyncErrorResVo(4, "工序链生成失败!", null, bom.getWorkOrderCode(), bom.getMaterCode(), bom.getMaterName(), bom.getPlmId(), bom.getStandards(), bom.getPartCount().toString(), bom.getErpParentCode(), null, bom.getDrawing()));
        }


        return workChain;
    }

    public ImportErpWorkOrder findDueDate(List<ImportErpWorkOrder> infoList) {
        if (infoList.size() == 1) {
            return infoList.get(0);

        }

        //过滤掉 3 和4  已取消的
        List<ImportErpWorkOrder> collectList = infoList
                .stream()
                .filter(s -> !s.getWorkOrderState().equals("3") && !s.getWorkOrderState().equals("4"))
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(collectList)) {
            return collectList.get(0);
        }

        //如果没有 就获取 计划开始时间不为空的
        for (ImportErpWorkOrder orderInfo : infoList) {
            if (orderInfo.getPlanStartTime() != null) {
                return orderInfo;
            }
        }
        return null;
    }
    public Integer getSerialNum(String constructNo, Integer orderType) {
        List<Order> list = orderMapper.lambdaQuery()
                .eq(Order::getConstructNo, constructNo)
                .eq(Order::getOrderType, orderType)
                .list();

        if (CollUtil.isNotEmpty(list)) {
            if (list.get(0).getSerialNum() == null) {
                Order max = orderMapper.lambdaQuery().eq(Order::getOrderType, orderType).orderByDesc(Order::getSerialNum).last(" limit 1").one();
                int serialCode = 0;
                if (max != null && max.getSerialNum() != null) {
                    serialCode = max.getSerialNum();
                }

                return serialCode + 1;
            } else {
                return list.get(0).getSerialNum();
            }
        } else {
            Order max = orderMapper.lambdaQuery().eq(Order::getOrderType, orderType).orderByDesc(Order::getSerialNum).last(" limit 1").one();
            int serialCode = 0;
            if (max != null && max.getSerialNum() != null) {
                serialCode = max.getSerialNum();
            }
            return serialCode + 1;

        }
    }

    @Transactional(readOnly = true)
    public BaseSelectResVo orderSelect() {

        List<ImportFrameOrder> orderList = importFrameOrderMapper.lambdaQuery().list();

        Map<Integer, String> map = new HashMap<>();
        for (Map.Entry<String, Integer> entry : ApsConstant.FRAME_TYPE.entrySet()) {
            map.put(entry.getValue(), entry.getKey());
        }

        List<BaseSelectItemResVo> collect = orderList.stream()
                .map(e -> {
                    BaseSelectItemResVo r = new BaseSelectItemResVo();
                    r.setText(e.getMyCode() + "-" + e.getName() + "-" + map.get(e.getType()));
                    r.setValue(e.getId());
                    return r;
                })
                .collect(Collectors.toList());
        return BaseSelectResVo.of(collect);
    }

    @Transactional
    public void orderMbd(ImportFrameOrderMbdReqVo reqVo) {
        ImportFrameOrder importFrameOrder = importFrameOrderMapper.selectById(reqVo.getId());
        List<ImportFrameBom> bomList = importFrameBomMapper.lambdaQuery().eq(ImportFrameBom::getOrderId, reqVo.getId()).list();
        List<ImportFramePhase> phaseList = importFramePhaseMapper.lambdaQuery().eq(ImportFramePhase::getOrderId, reqVo.getId()).list();

        String[] ignoreProp = new String[]{"id", "createDateTime", "modifyDateTime", "deleted", "createUsername", "modifyUsername", "factoryId"};

        Order newOrder = MkBeanUtils.copyProperties(importFrameOrder, Order.class, ignoreProp);
        newOrder.setOrderType(5);
        newOrder.setOrderCode(reqVo.getConstructCode());
        newOrder.setConstructNo(reqVo.getConstructCode());

        newOrder.setOrderName("架型-" + importFrameOrder.getName());
        Optional<ImportFrameBom> first = bomList.stream().filter(e -> e.getPid() == null).findFirst();
        if (first.isPresent()) {
            ImportFrameBom top = first.get();
            newOrder.setMaterName(top.getMaterName());
            newOrder.setMaterCode(top.getMaterCode());
            newOrder.setPlmId(top.getPlmId());
        } else {
            newOrder.setMaterName(importFrameOrder.getName());
            newOrder.setMaterCode(importFrameOrder.getMyCode());
            newOrder.setPlmId(importFrameOrder.getMyCode());
        }

        Order max = orderMapper.lambdaQuery()
                .in(Order::getOrderType, 2, 5)
                .ge(Order::getOrderStatus, 2)
                .eq(Order::getPlannedMonth, reqVo.getPlannedMonth())
                .isNotNull(Order::getSeq)
                .orderByDesc(Order::getSeq)
                .last("LIMIT 1")
                .one();

        newOrder.setOrderQty(1);
        newOrder.setFinishQty(0);
        newOrder.setOrderStatus(1);
        String suffix = OrderUtils.partType(newOrder.getPlmId(), newOrder.getMaterName());
        newOrder.setSuffix(suffix);
        newOrder.setFrameType(importFrameOrder.getMyCode());
        newOrder.setPlannedMonth(reqVo.getPlannedMonth());
        newOrder.setSeq(max == null ? 1 : max.getSeq() + 1);

        Factory line = factoryMapper.lambdaQuery().eq(Factory::getType, 2).eq(Factory::getMyCode, WorkshopProp.DEFAULT_LINE_CODE).one();
        newOrder.setLineId(line.getId());

        orderMapper.insert(newOrder);

        Map<Integer, Integer> newBomIdMap = new HashMap<>();
        Map<Integer, List<ImportFramePhase>> phaseBomIdMap = phaseList.stream().collect(Collectors.groupingBy(ImportFramePhase::getBomId));
        for (ImportFrameBom bom : bomList) {

            OrderBom newBom = MkBeanUtils.copyProperties(bom, OrderBom.class, ignoreProp);
            newBom.setOrderId(newOrder.getId());
            if (bom.getPid() != null) {
                newBom.setPid(newBomIdMap.getOrDefault(bom.getPid(), null));
            }
            orderBomMapper.insert(newBom);

            newBomIdMap.put(bom.getId(), newBom.getId());

            List<ImportFramePhase> importFramePhases = phaseBomIdMap.get(bom.getId());
            if(CollUtil.isEmpty(importFramePhases)){
                continue;
            }

            for (ImportFramePhase phase : importFramePhases) {
                OrderPhase newPhase = MkBeanUtils.copyProperties(phase, OrderPhase.class, ignoreProp);
                newPhase.setBomId(newBom.getId());
                newPhase.setOrderId(newOrder.getId());
                orderPhaseMapper.insert(newPhase);
            }

        }

        try {
            NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK_PRE);
            List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().eq(OrderBom::getOrderId, newOrder.getId()).eq(OrderBom::getMaterType, "Platepart").list();
            nestRule.partAdd(orderBomList);
        } catch (Exception e) {
            log.info("零件图纸同步失败。");
        }


        // -------------
        Order one = orderMapper.lambdaQuery()
                .in(Order::getOrderType, 2, 5)
                .ge(Order::getOrderStatus, 2)
                .eq(Order::getConstructNo, reqVo.getConstructCode())
                .last(" limit 1 ")
                .one();

        if(one == null){
            newOrder.setOrderStatus(2);
            orderMapper.updateById(newOrder);
            return ;
        }

        if(!one.getPlannedMonth().equals(reqVo.getPlannedMonth())){
            throw SyExceptionUtils.e("计划月份不一致,目标月份:{},当前月份:{}", one.getPlannedMonth(), reqVo.getPlannedMonth());
        }

        Integer minSeq = one.getSeq();

        List<Order> orderList = orderMapper.lambdaQuery()
                .eq(Order::getPlannedMonth, reqVo.getPlannedMonth())
                .in(Order::getOrderType, 2, 5)
                .ge(Order::getOrderStatus, 2)
                .ge(Order::getSeq, minSeq)
                .list();

        List<Order> eqOrder = orderList.stream().filter(e -> e.getConstructNo().equals(reqVo.getConstructCode())).collect(Collectors.toList());

        List<Order> neOrder = orderList.stream().filter(e -> !e.getConstructNo().equals(reqVo.getConstructCode())).collect(Collectors.toList());

        Map<String, Integer> orderTypes = new HashMap<>();
        orderTypes.put("D", 1);
        orderTypes.put("Z", 2);
        orderTypes.put("Y", 3);
        orderTypes.put("C", 4);
        orderTypes.put("L", 5);
        orderTypes.put("T", 6);
        orderTypes.put("B", 7);

        eqOrder.add(newOrder);
        eqOrder.sort(Comparator.comparing(e-> orderTypes.get(e.getSuffix())));

        neOrder.sort(Comparator.comparing(Order::getSeq));

        eqOrder.addAll(neOrder);
        newOrder.setOrderStatus(2);
        for (int i = 0; i < eqOrder.size(); i++) {
            Order ooo = eqOrder.get(i);
            ooo.setSeq(i + minSeq);
            orderMapper.updateById(ooo);
        }
        //

    }

    @Transactional
    public void orderErpAppend(ImportFrameOrderErpAppendReqVo reqVo) {
        ImportFrameOrder importFrameOrder = MkBeanUtils.copyProperties(reqVo, ImportFrameOrder.class, "id");
        importFrameOrderMapper.insert(importFrameOrder);

        ImportFrameOrderPubReqVo pubReqVo = new ImportFrameOrderPubReqVo();
        pubReqVo.setId(reqVo.getId());
        pubReqVo.setTargetId(importFrameOrder.getId());
        orderErp(pubReqVo);
    }

}
